package com.example.traning.mall.framework.web.core;

import com.example.traning.mall.framework.common.ex.ServiceException;
import com.example.traning.mall.framework.common.pojo.R;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.resource.NoResourceFoundException;

import static com.example.traning.mall.framework.common.ex.GlobalErrorCodeConstants.*;


/**
 * @author lei yu
 * @since 2025/04/27
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {


    @ExceptionHandler(value = Exception.class)
    public R exceptionHandler( Throwable ex) {

        // 处理 SpringMVC 请求地址不存在
        if (ex instanceof NoResourceFoundException e) {
            return R.error(NOT_FOUND.getCode(), String.format("请求地址不存在:%s", e.getResourcePath()));
        }

        // 处理 SpringMVC 请求方法不正确
        if (ex instanceof HttpRequestMethodNotSupportedException e) {
            return R.error(METHOD_NOT_ALLOWED.getCode(), String.format("请求方法不正确:%s", ex.getMessage()));
        }

        // 处理 SpringMVC 参数校验不正确
        if (ex instanceof MethodArgumentNotValidException e) {
            String errorMessage = e.getBindingResult().getAllErrors().getFirst().getDefaultMessage();
            return R.error(FORBIDDEN.getCode(), String.format("请求参数不正确：%s", errorMessage));
        }

        // 处理 Spring Security 权限不足的异常，来源是，使用 @PreAuthorize 注解，AOP 进行权限拦截
        if (ex instanceof AccessDeniedException e) {
            return R.error(FORBIDDEN);
        }

        // 处理业务异常
        if (ex instanceof ServiceException e) {
            return R.error(e.getCode(), e.getMessage());
        }

        log.warn("[兜底异常] {}", ExceptionUtils.getMessage(ex));
        log.warn("[兜底异常，打印堆栈]\n {}", ExceptionUtils.getStackTrace(ex));

        // 处理系统异常，兜底处理所有的一切
        return R.error(500, "服务器开小差了，请稍后重试");

    }
}
